package com.custom.action.condition;

import com.custom.action.condition.support.TableSupport;
import com.custom.action.interfaces.ColumnParseHandler;
import com.custom.action.util.DbUtil;
import com.custom.comm.enums.DbSymbol;
import com.custom.comm.enums.SqlExecTemplate;
import com.custom.comm.enums.SqlLike;
import com.custom.comm.utils.lambda.SFunction;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

/**
 * lambda表达式的条件构造对象
 * @author   Xiao-Bai
 * @since  2022/3/3 17:17
 **/
public class LambdaConditionWrapper<T> extends AbstractConditionWrapper<T, SFunction<T, ?>, LambdaConditionWrapper<T>> {


    @Override
    protected LambdaConditionWrapper<T> getInstance() {
        return new LambdaConditionWrapper<>(getEntityClass());
    }

    @Override
    protected String paramTransColumn(SFunction<T, ?> column) {
        ColumnParseHandler columnParseHandler = getColumnParseHandler();
        if (enableAlias) {
            return columnParseHandler.parseToColumn(column);
        }
        return columnParseHandler.parseToNormalColumn(column);
    }


    /**
     * 转成默认格式的条件构造器
     */
    public DefaultConditionWrapper<T> toDefault() {
        return new DefaultConditionWrapper<>(this);
    }

    public LambdaConditionWrapper(Class<T> entityClass) {
        wrapperInitialize(entityClass);
    }

    /**
     * 用在exists里
     * @param entityClass exists中的实体表
     * @param enableAlias exists中的实体表是否生成别名
     * <br/> 暂时没有地方可以供用户填入别名，所以默认为false，以table.column的方式替代
     */
    protected LambdaConditionWrapper(Class<T> entityClass, boolean enableAlias) {
        wrapperInitialize(entityClass, enableAlias);
    }

    public LambdaConditionWrapper(Class<T> entityClass, TableSupport tableSupport) {
        this.wrapperInitialize(entityClass, tableSupport);
    }


    LambdaConditionWrapper(ConditionWrapper<T> wrapper) {
        this.dataStructureInit();
        this.setEntityClass(wrapper.getEntityClass());
        this.setColumnParseHandler(wrapper.getColumnParseHandler());
        this.setTableSupport(wrapper.getTableSupport());
        this.setLastCondition(wrapper.getLastCondition());
        this.addCondition(wrapper.getFinalConditional());
        this.addParams(wrapper.getParamValues());
        this.setSelectColumns(wrapper.getSelectColumns());
        this.setPageParams(wrapper.getPageIndex(), wrapper.getPageSize());
        this.setPrimaryTable(wrapper.getPrimaryTable());
    }

    public <E> LambdaConditionWrapper<T> exists(ExistsWrapper<T, E> existsWrapper) {
        return exists(true, existsWrapper);
    }

    public <E> LambdaConditionWrapper<T> exists(boolean condition, ExistsWrapper<T, E> existsWrapper) {
        if (condition) {
            LambdaExistsWrapper<T, E> conditionWrapper = (LambdaExistsWrapper<T, E>) existsWrapper;
            addExistsSql(DbSymbol.EXISTS, conditionWrapper);
        }
        return childrenClass;
    }

    public <E> LambdaConditionWrapper<T> exists(Class<E> existClass, Consumer<ExistsWrapper<T, E>> existWrapper) {
        return exists(true, existClass, existWrapper);
    }

    public <E> LambdaConditionWrapper<T> exists(boolean condition, Class<E> existClass, Consumer<ExistsWrapper<T, E>> existWrapper) {
        if (condition) {
            LambdaExistsWrapper<T, E> existConditionWrapper = new LambdaExistsWrapper<>(existClass);
            existWrapper.accept(existConditionWrapper);
            addExistsSql(DbSymbol.EXISTS, existConditionWrapper);
        }
        return childrenClass;
    }

    public <E> LambdaConditionWrapper<T> notExists(ExistsWrapper<T, E> existsWrapper) {
        return exists(true, existsWrapper);
    }

    public <E> LambdaConditionWrapper<T> notExists(boolean condition, ExistsWrapper<T, E> existsWrapper) {
        if (condition) {
            LambdaExistsWrapper<T, E> conditionWrapper = (LambdaExistsWrapper<T, E>) existsWrapper;
            addExistsSql(DbSymbol.NOT_EXISTS, conditionWrapper);
        }
        return childrenClass;
    }

    public <E> LambdaConditionWrapper<T> notExists(Class<E> existClass, Consumer<ExistsWrapper<T, E>> existWrapper) {
        return exists(true, existClass, existWrapper);
    }

    public <E> LambdaConditionWrapper<T> notExists(boolean condition, Class<E> existClass, Consumer<ExistsWrapper<T, E>> existWrapper) {
        if (condition) {
            LambdaExistsWrapper<T, E> existConditionWrapper = new LambdaExistsWrapper<>(existClass);
            existWrapper.accept(existConditionWrapper);
            addExistsSql(DbSymbol.NOT_EXISTS, existConditionWrapper);
        }
        return childrenClass;
    }

    /**
     * 添加existsSql
     */
    protected <E> void addExistsSql(DbSymbol dbSymbol, LambdaExistsWrapper<T, E> existsWrapper) {
        LambdaConditionWrapper<E> lambdaConditionWrapper = existsWrapper.getWrapper();
        String table = lambdaConditionWrapper.getTableSupport().table();

        // exists 解析
        String existColumn = DbUtil.fullSqlColumn(table, existsWrapper.getExistColumn());
        String parseColumn = paramTransColumn(existsWrapper.getProColumn());
        String existsCondition = DbUtil.formatMapperSqlCondition(parseColumn, existColumn);

        String condition = existsCondition + lambdaConditionWrapper.getFinalConditional();
        String selectExistsSql = SqlExecTemplate.format(SqlExecTemplate.SELECT_EXISTS, table, condition);

        List<Object> paramValues = lambdaConditionWrapper.getParamValues();

        selectExistsSql = DbUtil.applyExistsCondition(getCurrAppendSymbol(), dbSymbol, selectExistsSql);

        addCondition(selectExistsSql);
        addParams(paramValues);
    }

}
